import { BilliardGame } from '../game/BilliardGame';
import { BallAttribute } from '../core/BallAttribute';
import { HumanAiSimulation } from './HumanAiSimulation';
import { HumanAiBrain } from '../ai/HumanAiBrain';
import { DeskBall, DeskHole, FreeKickPosition, HitPath } from '../ai/aicore';
import { HumanSetBallSimulation } from './HumanSetBallSimulation';
import { Databus } from '../core/Databus';
import { BattleCate, GameType } from '../core/Game';
import { Vec3 } from 'cc';
import { TableAtrribute } from '../core/TableAttribute';

const databus = Databus.Instance();
export class HumanAiController {
  private static instance = null as unknown as HumanAiController;
  private bestIndex = 0;
  private bestPathList: Array<HitPath> = [];
  public aiBrain = new HumanAiBrain(0);
  public simulation = new HumanAiSimulation();
  public setBallSimulation = new HumanSetBallSimulation();
  // 自由球的信息
  public isFreeKickBall = false;
  // 所有白球候选位置
  public candidateMainBallPositions: Array<FreeKickPosition> = [];
  public canIndex = 0;
  public changeFreeKickCount = 0;
  public static Instance() {
    if (!HumanAiController.instance) {
      HumanAiController.instance = new HumanAiController();
    }
    return HumanAiController.instance;
  }
  public clear() {
    this.canIndex = 0;
    this.changeFreeKickCount = 0;
  }
  public updateFrame(deltaTime: number) {
    this.simulateHuman();
  }
  // 模拟击球过程
  public simulateHuman() {
    // 自由球，模拟放置白球
    if (this.isFreeKickBall && !this.setBallSimulation.isEndSimulation()) {
      this.setBallSimulation.simulateHuman(this.candidateMainBallPositions[this.canIndex].pos);
      return;
    }
    // 自由球，当模拟完成瞄准方向，看看是否有更好的位置来放白球，如果有则替换掉重新选择自由球位置
    if (this.isFreeKickBall && this.simulation.isEndAimDirection()) {
      const { can, bestPathList, canIndex } = this.canRestartFreeKickBall();
      if (can) {
        this.bestPathList = bestPathList;
        this.setBallSimulation.startSimulation();
        this.simulation.startSimulation();
        this.changeFreeKickCount += 1;
        this.canIndex = canIndex;
        return;
      }
    }
    this.simulation.simulateHuman(this.bestPathList[this.bestIndex]);
  }

  public canRestartFreeKickBall() {
    if (this.changeFreeKickCount > 5) {
      return { can: false, bestPathList: null, canIndex: 0 };
    }
    if (this.canIndex + 1 >= this.candidateMainBallPositions.length) {
      return { can: false, bestPathList: null, canIndex: 0 };
    }
    
    const { mainBall, attackBallList, protectBallList, deskHoles } = this.computateBallListInfo();
    for (var idx=this.canIndex+1; idx<this.candidateMainBallPositions.length; idx++) {
      mainBall.setPosition(this.candidateMainBallPositions[idx].pos);
      const bestPathList = this.aiBrain.generateOnlyBestPath(mainBall, attackBallList, protectBallList, deskHoles);
      // 更换一次自由球的位置, 从头再来
      if (bestPathList.length > 0 && bestPathList[0].score > 1.01* this.bestPathList[0].score) {
        return { can: true, bestPathList: bestPathList, canIndex: idx };
      }
    }
    return { can: false, bestPathList: null, canIndex: 0 };
  }
  // 计算击球的选择
  public computateDeduction(isFreeKick: boolean, gameType: GameType, currentStep: number) {
    this.clear();
    this.isFreeKickBall = isFreeKick;
    const { mainBall, attackBallList, protectBallList, deskHoles } = this.computateBallListInfo();
    // 自由球  优先计算白球的位置
    if (this.isFreeKickBall) {
      this.candidateMainBallPositions = this.aiBrain.generateFreeKickBallPosition(attackBallList, protectBallList, deskHoles);
      mainBall.setPosition(this.candidateMainBallPositions[this.canIndex].pos);
      this.aiBrain.updateAiLevel(5);
    } else {
      this.aiBrain.updateAiLevel(databus.aiLevel);
    }
    this.bestPathList = this.aiBrain.generateAllBestPath(mainBall, attackBallList, protectBallList, deskHoles);
    this.setBallSimulation.startSimulation();
    this.simulation.startSimulation();
    this.bestIndex = 0;
    if (currentStep === 0) {
      this.computateFirstHitDeduction(gameType);
    }
    console.log('return best paths ', this.bestIndex, this.bestPathList);
  }

  // 计算默认瞄准的球/位置
  public defaultAimPosition(battleCate: BattleCate, gameType: GameType, currentStep: number) {
    if (currentStep === 0 && (battleCate.isNetBattle() || battleCate.isFrientBattle())) {
      if (gameType.isEightBall() || gameType.isNineBall()) {
        return new Vec3(0, TableAtrribute.DeskTopAxisY, 0);
      } else if (gameType.isSnooker()) {
        return new Vec3(-10, TableAtrribute.DeskTopAxisY, -2);
      }
    }
    const res = new Vec3(0, TableAtrribute.DeskTopAxisY, 0);
    const { mainBall, attackBallList, protectBallList, deskHoles } = this.computateBallListInfo();
    if (currentStep === 0 && (battleCate.isEndlessBattle() || battleCate.isFancyBattle())) {
      var minDist = 100000000;
      for (var i=0; i<attackBallList.length; i++) {
        const pos = attackBallList[i].position;

        const dist = (pos.x + 10) * (pos.x + 10) + pos.y * pos.y;
        if (dist < minDist) {
          minDist = dist;
          res.set(pos.x, TableAtrribute.DeskTopAxisY, pos.y);
        }
      }
      return res;
    }
    return this.aiBrain.generateBestHitPosition(mainBall, attackBallList, protectBallList, deskHoles);
  }

  // 计算当前用户击球 和 保护球的信息
  private computateBallListInfo() {
    const mb = BilliardGame.Instance().getMainWhiteBall();
    const mainBall = new DeskBall(mb.worldPosition.x, mb.worldPosition.z, 100, 0);

    const attackBallList: Array<DeskBall> = [];
    const protectBallList: Array<DeskBall> = [];
    const { hitBalls, protectBalls } = BilliardGame.Instance().getHitProtectBalls();
    for (const ball of hitBalls) {
      const ba = BallAttribute.getBallByName(ball.name);
      attackBallList.push(new DeskBall(ball.worldPosition.x, ball.worldPosition.z, ba.index, ba.score));
    }
    for (const ball of protectBalls) {
      const ba = BallAttribute.getBallByName(ball.name);
      protectBallList.push(new DeskBall(ball.worldPosition.x, ball.worldPosition.z, ba.index, ba.score));
    }

    const deskHoles = Array<DeskHole>();
    const holes = BilliardGame.Instance().getDeskInHolePosition();
    var holeIndex = 1;
    for (var i=0; i<holes.length; i++) {
      deskHoles.push(new DeskHole(holes[i].x, holes[i].z, holeIndex++));
    }
    console.log('xxxxx holes ', deskHoles);
    return { mainBall, attackBallList, protectBallList, deskHoles };
  }
  // 计算第1杆击球
  private computateFirstHitDeduction(gameType: GameType) {
    if (gameType.isEightBall() || gameType.isNineBall()) {
      var minDist = 100000000;
      const dx = -15 + 4 * Math.random();
      const dy = 3 * (Math.random() - 0.5);
      for (var i=0; i<this.bestPathList.length; i++) {
        const dist = (this.bestPathList[i].targetPos.x - dx) * (this.bestPathList[i].targetPos.x - dx) + (this.bestPathList[i].targetPos.y - dy) * (this.bestPathList[i].targetPos.y - dy);
        if (dist < minDist) {
          this.bestIndex = i;
          minDist = dist;
        }
      }
      return;
    }
    if (gameType.isSnooker()) {
      var minDist = 100000000;
      const dx = -14 + 4 * Math.random();
      const dy = -2.5 * Math.random();
      for (var i=0; i<this.bestPathList.length; i++) {
        const dist = (this.bestPathList[i].targetPos.x - dx) * (this.bestPathList[i].targetPos.x - dx) + (this.bestPathList[i].targetPos.y - dy) * (this.bestPathList[i].targetPos.y - dy);
        if (dist < minDist) {
          this.bestIndex = i;
          minDist = dist;
        }
      }
      return;
    }
  }
}

